package math.dataset;

/**
 * Useful class for doing simple statistical analysis of data.
 * Note all methods are implemented such that calculations will only need
 * to be performed once, then subsequent calls to the same method will not
 * involve any calculations as the results are stored. For example,
 * the getMean() method will calculate the mean of the values the first
 * time it is called, but the result will be stored in an instance variable.
 * Hence, the next time getMean() is called, the stored result is returned
 * without needing to recalculate. These instance variables are set to
 * null during instantiation, and the methods check if an instance variable
 * is null then performs calculations if it is, otherwise it'll simply
 * return the value of the instance variable. All methods in this class
 * are implemented this way.
 *
 * @author Shimu
 */
public class DataSet_1V extends DataSet_Float {

    private float[] data;

    private int size;

    private Float mean, median, min, max, variance, standardDeviation;

    private boolean sorted;

    public DataSet_1V(float[] data) {
        if (data == null) {
            this.data = new float[0];
        } else {
            this.data = data;
        }

        this.size = data.length;
        this.mean = null;
        this.median = null;
        this.min = null;
        this.max = null;
        this.variance = null;
        this.standardDeviation = null;
        this.sorted = false;
    }

    /**
     * Return the size of the dataset.
     * @return the size of the dataset.
     */
    public int getSize() {
        return size;
    }

    /**
     * Returns the mean (average) of this dataset, null if the data is empty.
     * Uses DataSet's getMean(float[]) method.
     *
     * @see DataSet.getMean(float[])
     * @return the mean (average) of this dataset, null if the data is empty
     */
    public Float getMean() {
        if (this.mean == null) {
            mean = getMean(this.data);
        }
        return mean;
    }

    /**
     * Returns the median (middle number) of this dataset, null if the data
     * is empty. Uses DataSet's getMedian(boolean, float[]) method.
     *
     * @see DataSet.getMedian(boolean, float[])
     * @return the median of this dataset, null if the data is empty.
     */
    public Float getMedian() {
        if (this.median == null) {
            median = getMedian(sorted, data);
        }
        return median;
    }

    /**
     * Returns the minimum value of this dataset, null if the data is empty.
     * Uses DataSet's getMin(boolean, float[]) method.
     *
     * @see DataSet.getMin(boolean, float[])
     * @return the minimum value of this dataset, null if the data is empty.
     */
    public Float getMin() {
        if (this.min == null) {
            //this.min = getMin(sorted, data);
            this.min = getMin(data);
        }
        return min;
    }

    /**
     * Returns the maximum value of this dataset, null if the data is empty.
     * Uses DataSet's getMax(boolean, float[]) method.
     *
     * @see DataSet.getMax(boolean, float[])
     * @return the maximum value of this dataset.
     */
    public Float getMax() {
        if (this.max == null) {
            //this.max = getMax(sorted, data);
            this.max = getMax(data);
        }
        return max;
    }

    /**
     * Returns the variance of this dataset, null if the data is empty.
     * Uses DataSet's getVariance(float[], float) method.
     *
     * @see DataSet.getVariance(float[], float)
     * @return the variance of the dataset, null if the data is empty.
     */
    public Float getVariance() {
        if (this.variance == null) {
            this.variance = getVariance(data, getMean());
        }
        return variance;
    }

    /**
     * Returns the standard deviation of this dataset, null if the data is
     * empty, 0 if the data contains only one value. Uses DataSet's
     * getStandardDeviation(float) method.
     *
     * @see DataSet.getStandardDeviation(float)
     * @return
     */
    public Float getStandardDeviation() {
        if (this.standardDeviation == null) {
            this.standardDeviation = getStandardDeviation(getVariance());
        }
        return standardDeviation;
    }

    /**
     * Given a value from this dataset, returns the z-score of that value.
     * Note this method does not store the z-score. Uses DataSet's
     * getZScore(float, float, float) method.
     * 
     * @param value a value from this dataset
     * @return the z-score of that value.
     */
    public Float getZScore(float value) {
        return getZScore(value, this.mean, this.standardDeviation);
    }
}
